package sunsun.xiaoli.jiarebang.utils;

import android.util.Log;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import com.itboye.pondteam.utils.Const;
import com.itboye.pondteam.utils.LogUtils;
import com.itboye.pondteam.utils.loadingutil.MAlert;
import com.itboye.pondteam.volley.DESUtil;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import org.json.JSONTokener;
import sunsun.xiaoli.jiarebang.beans.BaseChatResponse;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.reflect.Type;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.SocketAddress;
import java.net.SocketException;
import java.util.ArrayList;

import static sunsun.xiaoli.jiarebang.utils.BaseConversion.byte2hex;
import static sunsun.xiaoli.jiarebang.utils.BaseConversion.byteToInt;
import static sunsun.xiaoli.jiarebang.utils.BaseConversion.toStringHex;

public class ChatTcp {
    private static ChatTcp instance;
    public static String TAG = "chat_socket";
    private Socket socket;
    private boolean flag = true;
    SocketListener mSocketListener;

    /**
     * {"id":0,"type":"19999","timestamp":1543211094,"content":"5T1oZEzFGu\/KTdh+luJkRApqIQrYR1ZE","sign":"091208379dcf57d4a5202a7679f4102f"}
     *
     * @return
     */
    public synchronized static ChatTcp getInstance() {
        if (instance == null) {
            instance = new ChatTcp();
        }
        return instance;
    }

    public void setmSocketListener(SocketListener socketListener) {
        mSocketListener = socketListener;
    }

    public void connecSocket(String IP, int PROT) {
//        if (socket != null)
//            socket = null;
        LogUtils.v(TAG, "Ready to connect...");
        lastMessageTime = System.currentTimeMillis();
        SendThread sThread = new SendThread(IP, PROT);
        sThread.start();
    }

    public void sendProtocol(String msg) {
        if (socket != null) {
            try {
                OutputStream os = socket.getOutputStream();
//                os.write(msg.getBytes("UTF-8"));
                os.write(msg.getBytes("UTF-8"));
                LogUtils.v(TAG, "sendProtocol: " + msg);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

    }

    boolean result = false;

    public boolean sendProtocol(byte[] b) {
        new Thread() {
            @Override
            public void run() {
                if (socket != null) {
                    try {
                        OutputStream os = socket.getOutputStream();
                        os.write(b);
                        LogUtils.v(TAG, "send byte[] length：" + (b.length));
                        result = true;
                    } catch (IOException e) {
                        e.printStackTrace();
                        result = false;
                    }
                }
            }
        }.start();
        return result;
    }

    long lastMessageTime = System.currentTimeMillis();//上一次消息发送时间

    public boolean sendChatMessage(String nickName, String uid, String role, String roomId, String content) {
        long temp = System.currentTimeMillis();
        if (temp - lastMessageTime <= 3000) {
            MAlert.alert("消息发送频率不能超过3秒");
            return false;
        }
        lastMessageTime = System.currentTimeMillis();
        return sendProtocol(new ChatParams().sendParamsMap(nickName, uid, role, roomId, content));
    }

    public boolean sendChatMessage(String nickName, String uid, String toUid, String role, String roomId, String content) {
        long temp = System.currentTimeMillis();
        if (temp - lastMessageTime <= 3000) {
            MAlert.alert("消息发送频率不能超过3秒");
            return false;
        }
        lastMessageTime = System.currentTimeMillis();
        return sendProtocol(new ChatParams().sendParamsMap(nickName, uid, toUid, role, roomId, content));
    }

    public boolean sendEnterLivingRoomMessage(String nickName, String uid, String roomId) {
        return sendProtocol(new ChatParams().enterLivingRoom(nickName, uid, roomId));
    }

    public boolean sendLeaveLivingRoomMessage(String uid, String roomId) {
        return sendProtocol(new ChatParams().exitLivingRoom(uid, roomId));
    }

    public boolean forbidUser(String uid, String roomId, String nick) {
        return sendProtocol(new ChatParams().forbidUser(uid, roomId, nick));
    }

    public boolean resumeUser(String uid, String roomId, String nick) {
        return sendProtocol(new ChatParams().resumeUser(uid, roomId, nick));
    }

    public void closeSocket() {
        if (socket != null) {
            try {
                flag = false;
                socket.close();
                socket = null;
                LogUtils.v(TAG, "Disconnect...");
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    int count = 0;

    class SendThread extends Thread {
        String ip;
        int port;

        public SendThread(String ip, int port) {
            // TODO Auto-generated constructor stub
            this.ip = ip;
            this.port = port;
        }

        @Override
        public void run() {
            // TODO Auto-generated method stub
            super.run();
            socket = null;
            socket = new Socket();
            try {
                byte buffer[] = new byte[1024 * 2];
                count++;
                LogUtils.v(TAG, "正在连接socket");
//                if (count == 3) {
//                    this.ip = "chat-server.sunsunxiaoli.com";
//                }
//                SocketAddress socAddress = new InetSocketAddress(this.netAdress, this.port);
                InetSocketAddress socAddress = new InetSocketAddress(this.ip, this.port);
                if (socket != null) {
                    socket.connect(socAddress, 2000);
                }

                LogUtils.v(TAG, "Connect server success  " + ip + ",port：" + port);
                flag = true;
                if (socket == null) {
                    return;
                }
                while (flag) {

                    if (socket.isClosed()) {
                        flag = false;
                        socket = null;
                    }
                    InputStream isInputStream = socket.getInputStream();
                    int lenth = isInputStream.read(buffer);
                    if (lenth <= 0) {
//                        socket.close();
                        continue;
                    }

                    byte[] bytess = new byte[lenth];
                    System.arraycopy(buffer, 0, bytess, 0, lenth);//处理掉多余的无效byte
                    //////粘包测试
//                    System.arraycopy(buffer, 0, bytess, lenth, lenth);
//                    System.arraycopy(buffer, 0, bytess, lenth * 2, lenth);
                    /////粘包测试
                    int totalLength = 0;
                    int contentLength = bytess.length;
                    while (totalLength < contentLength) {
                        if (totalLength + 4 < bytess.length) {
                            int length = BaseConversion.byteToInt(bytess[totalLength]) * 256 * 256 * 256 + BaseConversion.byteToInt(bytess[totalLength + 1]) * 256 * 256 + BaseConversion.byteToInt(bytess[totalLength + 2]) * 256 + BaseConversion.byteToInt(bytess[totalLength + 3]);
                            byte[] bytes = new byte[length];
                            System.arraycopy(bytess, totalLength + 4, bytes, 0, length);
                            String tempContent = new String(bytes, 0, bytes.length, "gb2312").replaceAll("\u0000", "").replaceAll("\\\\", "");
                            totalLength = totalLength + 4 + length;
                            handleData(tempContent);
                        } else {
                            break;
                        }
                    }
                }
            } catch (SocketException e) {
//                closeSocket();
                connecSocket(this.ip, this.port);
                LogUtils.v(TAG, "Connect fail, socket Exception：" + e.getMessage());
                e.printStackTrace();
            } catch (IOException e) {
//                closeSocket();
                connecSocket(this.ip, this.port);
                LogUtils.v(TAG, "Connect fail IO Exception：" + e.getMessage());
                e.printStackTrace();
            }catch (Exception e){
                connecSocket(this.ip, this.port);
            }
        }
    }

    private void handleData(String hexString) {
        //对参数进行解密操作
        LogUtils.v(TAG, "receive data to hex：" + hexString);
        if (hexString.startsWith("[")) {
            hexString = hexString.replace("}\"", "}").replace("\"{", "{");
        }
        Object object = null;
        try {
            object = new JSONTokener(hexString).nextValue();
            ArrayList<BaseChatResponse> chatResponseArrayList = new ArrayList<>();
            if (object instanceof JSONObject) {
                Type type = new TypeToken<BaseChatResponse>() {
                }.getType();
                BaseChatResponse chatResponse = new Gson().fromJson(hexString, type);
                String deData = DESUtil.decode(chatResponse.getContent(), Const.CHAT_KEY);
                LogUtils.v(ChatTcp.TAG, "JSON 解析后 JSONObject：" + deData);
                if (!deData.equals("[]")) {
                    Type typeJsonObject = new TypeToken<BaseChatResponse.ContentBean>() {
                    }.getType();
                    BaseChatResponse.ContentBean contentBean = new Gson().fromJson(deData, typeJsonObject);
                    chatResponse.setContentBean(contentBean);
                    chatResponseArrayList.add(chatResponse);
                }
            } else if (object instanceof JSONArray) {
                Type type = new TypeToken<ArrayList<BaseChatResponse>>() {
                }.getType();
                chatResponseArrayList = new Gson().fromJson(hexString, type);
                for (int i = 0; i < chatResponseArrayList.size(); i++) {
                    String contentTemp = chatResponseArrayList.get(i).getContent();
                    String deData = DESUtil.decode(contentTemp, Const.CHAT_KEY);
                    chatResponseArrayList.get(i).setDecodeData(deData);
                    //将解析后的data转成实体类对象
                    BaseChatResponse.ContentBean contentBean = new Gson().fromJson(deData, BaseChatResponse.ContentBean.class);
                    chatResponseArrayList.get(i).setContentBean(contentBean);
                    LogUtils.v(ChatTcp.TAG, "JSON 解析后 JSONArray：" + deData);
                }
            }
            if (chatResponseArrayList != null) {
                if (chatResponseArrayList.size() > 0 && mSocketListener != null) {
                    mSocketListener.onResponse(chatResponseArrayList);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
            LogUtils.v(TAG, "receive data JSON Exception：" + e.getMessage());
        }
    }


    public interface SocketListener {
        void onResponse(ArrayList<BaseChatResponse> data);
    }
}
